package com.yixing.tech.wms.service.impl;

import com.yixing.tech.common.base.CustomAggregationOperation;
import com.yixing.tech.common.service.AbstractWmsService;
import com.yixing.tech.wms.service.StorageLocationService;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.util.LinkedList;
import java.util.List;

import static com.yixing.tech.common.CommonConstant.*;

/**
 * StorageLocationService
 *
 * @author yixing tech
 * @since 1.0.0
 */
@Service
public class StorageLocationServiceImpl extends AbstractWmsService implements StorageLocationService {

    /**
     * 查询库位上的空容器列表
     *
     * @param containerType 容器类型
     * @param areas         库区
     * @return not null
     */
    @Override
    public List<Document> queryEmptyContainer(String containerType, List<String> areas) {
        // 从库位中查询容器
        Criteria emptyMatch = newCriteria()
                .and("area").in(areas)
                .and("lock").is(false);
        List<AggregationOperation> emptyOperations = new LinkedList<>();
        emptyOperations.add(Aggregation.match(emptyMatch));
        // 匹配容器，容器不能锁，容器类型匹配
        String lookupContainer = "{ $lookup:{ " +
                "from:'entity_" + CONTAINER + "'," +
                "let:{ containerCode:'$containerCode'}," +
                "pipeline:[" +
                "{$match:{$and:[{$expr:{$eq:['$code','$$containerCode']}},{$expr:{$eq:['$isDelete',0]}}, " +
                "{$expr:{$eq:['$lock', false]}} ]}}" +
                "{$project:{code:1,type:1,capacity:1,lock:1}}" +
                "]," +
                "as:'container'}}";
        emptyOperations.add(new CustomAggregationOperation(lookupContainer));
        emptyOperations.add(Aggregation.unwind("container", true));
        emptyOperations.add(Aggregation.match(Criteria.where("container.lock").is(false)
                .and("container.type").is(newDocument("id", new ObjectId(containerType)))));

        // 筛选容器，必须是空容器
        String lookupStock = "{ $lookup:{ " +
                "from:'entity_" + STOCK_NAME + "'," +
                "let:{ containerCode:'$containerCode'}," +
                "pipeline:[" +
                "{$match:{$and:[{$expr:{$eq:['$containerCode','$$containerCode']}},{$expr:{$eq:['$isDelete',0]}}, " +
                "{$expr:{$gt:['realNum', 0]}} ]}}" +
                "{$project:{containerCode:1}}" +
                "]," +
                "as:'stock'}}";
        emptyOperations.add(new CustomAggregationOperation(lookupStock));
//        emptyOperations.add(Aggregation.unwind("stock", true));
        emptyOperations.add(Aggregation.match(Criteria.where("stock").size(0)));

        // 关联库区
        String lookupStorageArea = "{ $lookup:{ " +
                "from:'entity_" + STOCK_AREA + "'," +
                "let:{ areaCode:'$area'}," +
                "pipeline:[" +
                "{$match:{$and:[{$expr:{$eq:['$code','$$areaCode']}},{$expr:{$eq:['$isDelete',0]}}]}}" +
                "{$project:{code:1,name:1,warehouse:1,storageType:1}}" +
                "]," +
                "as:'stroageArea'}}";
        emptyOperations.add(new CustomAggregationOperation(lookupStorageArea));
        emptyOperations.add(Aggregation.unwind("stroageArea", true));

        // 关联仓库
        String lookupStorage = "{ $lookup:{ " +
                "from:'entity_" + WARE_HOUSE + "'," +
                "let:{ warehouseCode:'$stroageArea.warehouse'}," +
                "pipeline:[" +
                "{$match:{$and:[{$expr:{$eq:['$code','$$warehouseCode']}},{$expr:{$eq:['$isDelete',0]}}]}}" +
                "{$project:{code:1,stockName:1}}" +
                "]," +
                "as:'stroage'}}";
        emptyOperations.add(new CustomAggregationOperation(lookupStorage));
        emptyOperations.add(Aggregation.unwind("stroage", true));

        // 仓库信息
        emptyOperations.add(Aggregation.addFields()
                        .addFieldWithValue("warehouseCode", "$stroage.code")
                        .addFieldWithValue("areaCode", "$stroageArea.code")
                        .addFieldWithValue("locationCode", "$code")
                .build());

        List<Document> documents = aggregateResult(emptyOperations, "entity_" + STOCK_LOCATION);
        return documents;
    }
}
